package com.lcz.highfunction

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Button
import java.sql.Struct

class MainActivity : AppCompatActivity() {
    val TAG = "MainActivity"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        var list = arrayListOf<Student>()
        list.add(Student("张三", 10))
        list.add(Student("李四", 15))
        list.add(Student("王五", 20))
        list.add(Student("赵六", 25))

        findViewById<Button>(R.id.btn_findName).setOnClickListener {
            var find = findName(list, "李四")
            if (find == null) {
                Log.i(TAG, "没找到")
            } else {
                Log.i(TAG, "找到了:${find}")
            }
        }
        findViewById<Button>(R.id.btn_findAge).setOnClickListener {
            var find = findAge(list, 20)
            if (find == null) {
                Log.i(TAG, "没找到")
            } else {
                Log.i(TAG, "找到了:${find}")
            }
        }
        findViewById<Button>(R.id.btn_high_findName).setOnClickListener {
            //看到了吗?这里第二个参数我传了一个{}.这就是一段代码当参数. 这样写是最标准但不常用的写法.可以简写
            //highFind(list, { }) 可以简写成 highFind(list) { } 也就是把第二个参数不写到参数的位置.看起来好像传了一个参数.后边是函数体. 这也是很多人看不懂kotlin的关键点.
            //下边是标准写法
            var find = highFind(list, { item: Student ->
                var pipei = false
                if (item.name.equals("李四")) {
                    pipei = true
                }else{
                    pipei = false
                }
                //最后一行写什么就是这个代块的返回值.相当于return peipi.  但是真这么写会报错.只能把返回值直接写到最后一行,删掉return
                pipei
            })
            //下边是简写(最常用,但不易理解)
//            var find = highFind(list) { item: Student ->
//                var pipei = false
//                if (item.name.equals("李四")) {
//                    pipei = true
//                }else{
//                    pipei = false
//                }
//                //最后一行写什么就是这个代块的返回值.相当于return peipi.  但是真这么写会报错.只能把返回值直接写到最后一行,删掉return
//                pipei
//            }


            if (find == null) {
                Log.i(TAG, "没找到")
            } else {
                Log.i(TAG, "找到了:${find}")
            }

        }

        findViewById<Button>(R.id.btn_high_findAge).setOnClickListener {

            //下边是简写(最常用,但不易理解)
            var find = highFind(list) { item: Student ->
                var pipei = false
                if (item.age == 20) {
                    pipei = true
                }else{
                    pipei = false
                }
                //最后一行写什么就是这个代块的返回值.相当于return peipi.  但是真这么写会报错.只能把返回值直接写到最后一行,删掉return
                pipei
            }

            if (find == null) {
                Log.i(TAG, "没找到")
            } else {
                Log.i(TAG, "找到了:${find}")
            }

        }

        //可以看到定义了一个高阶函数,但能做更多的事,更灵活.
        //假如我要找年龄大于25的.普通函数还要在写一个方法.然而目前的高阶函数还是不用动,就能完成此需求
    }

    //普通写法.找到姓名匹配的.并返回
    fun findName(list: ArrayList<Student>, findName: String): Student? {

        //就是遍历,不用关心遍历的写法
        for (i in 0 until list.size) {
            var item = list.get(i)
            if (item.name.equals(findName)) {
                return item
            }
        }
        return null
    }

    //普通写法.找到年龄匹配的.并返回
    fun findAge(list: ArrayList<Student>, findAge: Int): Student? {

        //就是遍历,不用关心遍历的写法
        for (i in 0 until list.size) {
            var item = list.get(i)
            if (item.age == findAge) {
                return item
            }
        }
        return null
    }

    //高阶函数. 找姓名,年龄,或者其他一些条件.具体什么条件,调用者说了算
    /**
     *
     * @param list ArrayList<Student>
     * @param block 匹配条件.虽然条件调用者可以随便传.但是我规定了条件的大致格式.这个格式必须按我的来
     *   什么格式呢? 就是我传给调用者一个student,调用者判断后,给我返回一个boolean值.我只关心这个boolean值
     * @return Student?
     */
    fun highFind(list: ArrayList<Student>, block: (item: Student) -> Boolean): Student? {

        //就是遍历,不用关心遍历的写法
        for (i in 0 until list.size) {
            var item = list.get(i)
            //调用传过来的匹配条件,看看是否匹配上了.
            //block.invoke(item) 的意思是. 执行block这段函数代码,并且传递给block一个参数item
            var 匹配 = block.invoke(item)
            if (匹配) {
                return item
            }
        }
        return null
    }
}

//定义一个学生类.不用纠结写法,就和java的类差不多,只不过写起来简单.toString,get,set都自动有了
data class Student(var name: String, var age: Int)